package org.cs456;

import org.cs456.data.Image;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.media.ExifInterface;
import android.os.Bundle;
import android.util.FloatMath;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

public class ImageActivity extends Activity implements OnTouchListener {
	private Image img;
	Button metadata;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.image_layout);
		metadata = (Button) findViewById(R.id.meta_data_button);

		setImage(imgId);
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		ImageView vw = (ImageView) findViewById(R.id.image);
		if(vw != null){
			vw.setImageBitmap(null);
			System.gc();
		}
		Log.v("CS456 - ImageActivity", "onDestroy'd");
	}

	public void viewMain(View view) {
		Intent myIntent = new Intent(view.getContext(), MainActivity.class);
		startActivityForResult(myIntent, 0);
	}

	public boolean onTouch(View v, MotionEvent event) {
		ImageView view = (ImageView) v;

		// Handle touch events here...
		switch (event.getAction() & MotionEvent.ACTION_MASK) {
		case MotionEvent.ACTION_DOWN:
			savedMatrix.set(matrix);
			start.set(event.getX(), event.getY());
			mode = DRAG;
			break;
		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_POINTER_UP:
			mode = NONE;
			break;
		case MotionEvent.ACTION_POINTER_DOWN:
			oldDist = spacing(event);
			savedMatrix.set(matrix);
			midPoint(mid, event);
			mode = ZOOM;
			break;

		case MotionEvent.ACTION_MOVE:
			if (mode == DRAG) {
				matrix.set(savedMatrix);
				matrix.postTranslate(event.getX() - start.x, event.getY()
						- start.y);
			} else if (mode == ZOOM) {
				float newDist = spacing(event);
				matrix.set(savedMatrix);
				float scale = newDist / oldDist;
				matrix.postScale(scale, scale, mid.x, mid.y);
			}
			break;
		}

		// Perform the transformation
		view.setImageMatrix(matrix);
		return true; // indicate event was handled
	}

	public void nextImage(View view) {
		setImage(imgId);
	}

	public void viewMetaData(View view) {
		setContentView(R.layout.metadata_layout);
		TextView vw = (TextView) findViewById(R.id.meta_data);

		String myAttribute = new String();
		myAttribute += getTagString(ExifInterface.TAG_FOCAL_LENGTH, img.EXIF);
		myAttribute += getTagString(ExifInterface.TAG_DATETIME, img.EXIF);
		myAttribute += getTagString(ExifInterface.TAG_FLASH, img.EXIF);
		myAttribute += getTagString(ExifInterface.TAG_GPS_LATITUDE, img.EXIF);
		myAttribute += getTagString(ExifInterface.TAG_GPS_LATITUDE_REF,
				img.EXIF);
		myAttribute += getTagString(ExifInterface.TAG_GPS_LONGITUDE, img.EXIF);
		myAttribute += getTagString(ExifInterface.TAG_GPS_LONGITUDE_REF,
				img.EXIF);
		myAttribute += getTagString("GPSAltitude", img.EXIF);

		myAttribute += getTagString(ExifInterface.TAG_IMAGE_LENGTH, img.EXIF);
		myAttribute += getTagString(ExifInterface.TAG_IMAGE_WIDTH, img.EXIF);
		myAttribute += getTagString(ExifInterface.TAG_MAKE, img.EXIF);
		myAttribute += getTagString(ExifInterface.TAG_MODEL, img.EXIF);
		myAttribute += getTagString(ExifInterface.TAG_ORIENTATION, img.EXIF);
		myAttribute += getTagString(ExifInterface.TAG_WHITE_BALANCE, img.EXIF);
		vw.setText(myAttribute);
	}

	private String getTagString(String tag, ExifInterface exif) {
		return (tag + " : " + exif.getAttribute(tag) + "\n");
	}

	// Private Methods
	// ------------------------------------------------------------
	private void setImage(int imgNum) {
		ImageView vw = (ImageView) findViewById(R.id.image);
		vw.setImageBitmap(null);
		System.gc();
		img = Image.find(this, imgNum);
		initImageScaling();

		if (img != null) {
			metadata.setVisibility(Button.VISIBLE);
			vw.setImageURI(img.getURI());
			scaleImage(vw);

		} else {
			vw.setImageResource(R.drawable.icon);
			metadata.setVisibility(Button.GONE);
		}
		vw.setImageMatrix(matrix);
		vw.setOnTouchListener(this);
		
		int imgCount = (int) Image.count(this);
		if (imgCount > 0)
			imgId = imgId % imgCount + 1;
	}

	private void scaleImage(ImageView vw) {
		Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
				.getDefaultDisplay();
		float scale = (float) Math.min(display.getHeight(), display.getWidth()) / 
						(float) Math.max(img.getHeight(), img.getWidth());
		
		matrix.postScale(scale, scale);
		savedMatrix.postScale(scale, scale);

		vw.setImageMatrix(matrix);
	}

	private float spacing(MotionEvent event) {
		float x = event.getX(0) - event.getX(1);
		float y = event.getY(0) - event.getY(1);
		return FloatMath.sqrt(x * x + y * y);
	}

	private void midPoint(PointF point, MotionEvent event) {
		float x = event.getX(0) + event.getX(1);
		float y = event.getY(0) + event.getY(1);
		point.set(x / 2, y / 2);
	}

	private void initImageScaling() {
		matrix = new Matrix();
		savedMatrix = new Matrix();
		start = new PointF();
		mid = new PointF();
		oldDist = 0;

	}

	// Private Members
	// ------------------------------------------------------------

	// These matrices will be used to move and zoom image
	private Matrix matrix = null;
	private Matrix savedMatrix = null;

	// We can be in one of these 3 states
	private static final int NONE = 0;
	private static final int DRAG = 1;
	private static final int ZOOM = 2;
	private int mode = NONE;

	// Used to determine the image transformation.
	private PointF start = null;
	private float oldDist = 0;
	private PointF mid = null;

	// Hack to easily switch between images.
	private int imgId = 1;

}
